package com.qiaoba.module.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.qiaoba.api.auth.service.OnlineUserApiService;
import com.qiaoba.api.auth.utils.SecurityUtil;
import com.qiaoba.api.system.entity.dto.SysUserDTO;
import com.qiaoba.api.system.entity.dto.UserResetPwdDTO;
import com.qiaoba.api.system.entity.dto.UserUpdateStatusDTO;
import com.qiaoba.api.system.entity.vo.SysUserVO;
import com.qiaoba.common.base.exception.ServiceException;
import com.qiaoba.module.system.converter.SysUserConverter;
import com.qiaoba.module.system.entity.SysUser;
import com.qiaoba.module.system.entity.param.SysUserParam;
import com.qiaoba.module.system.mapper.SysUserMapper;
import com.qiaoba.module.system.service.SysUserPostService;
import com.qiaoba.module.system.service.SysUserRoleService;
import com.qiaoba.module.system.service.SysUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 用户 服务层实现
 *
 * @author ailanyin
 * @date 2023-09-13 20:57:43
 */
@Service
@RequiredArgsConstructor
public class SysUserServiceImpl implements SysUserService {

    private final SysUserMapper sysUserMapper;
    private final SysUserRoleService sysUserRoleService;
    private final SysUserPostService sysUserPostService;
    private final OnlineUserApiService onlineUserApiService;

    @Override
    public List<SysUserVO> selectVoList(SysUserParam param) {
        return sysUserMapper.selectVoList(param);
    }

    @Override
    public SysUser selectById(String userId, boolean allowNull) {
        SysUser sysUser = sysUserMapper.selectById(userId);
        if (!allowNull && Objects.isNull(sysUser)) {
            throw new ServiceException(StrUtil.format("查询用户不存在, ID: {}", userId));
        }
        return sysUser;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int saveOrUpdate(SysUserDTO dto, Boolean isUpdate) {
        int result = 0;
        // 检查相关参数是否已存在
        checkAllowAddOrUpdate(dto);
        // 类型转换
        SysUser sysUser = SysUserConverter.dto2Entity(dto);
        if (isUpdate) {
            // 不更新账号和密码
            sysUser.setPassword(null);
            sysUser.setUsername(null);
            // 更新sysUser
            result = sysUserMapper.updateById(sysUser);
        } else {
            // 处理密码
            sysUser.setPassword(SecurityUtil.encryptPassword(dto.getPassword()));
            // 插入sysUser
            result = sysUserMapper.insert(sysUser);
        }
        // 处理角色
        sysUserRoleService.updateUserRole(sysUser.getUserId(), dto.getRoleIds(), isUpdate);
        // 处理岗位
        sysUserPostService.updateUserPost(sysUser.getUserId(), dto.getPostIds(), isUpdate);
        return result;
    }

    @Override
    public int resetPwd(UserResetPwdDTO dto) {
        SysUser sysUser = new SysUser();
        sysUser.setUserId(dto.getUserId());
        sysUser.setPassword(SecurityUtil.encryptPassword(dto.getPassword()));
        return sysUserMapper.updateById(sysUser);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateStatus(UserUpdateStatusDTO dto) {
        SysUser sysUser = new SysUser();
        sysUser.setUserId(dto.getUserId());
        sysUser.setStatus(dto.getStatus());
        int result = sysUserMapper.updateById(sysUser);
        if (result > 0) {
            // userId查询username
            SysUser user = sysUserMapper.selectById(dto.getUserId());
            // 删除Redis中用户缓存信息
            onlineUserApiService.deleteByUsername(user.getUsername());
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteById(String userId) {
        return deleteByIds(CollUtil.toList(userId));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteByIds(List<String> userIds) {
        // 删除和角色绑定
        sysUserRoleService.deleteByUserIds(userIds);
        // 删除和岗位绑定
        sysUserPostService.deleteByUserIds(userIds);
        // 删除用户
        return sysUserMapper.deleteBatchIds(userIds);
    }

    @Override
    public int updateById(SysUser sysUser) {
        return sysUserMapper.updateById(sysUser);
    }

    @Override
    public void checkAllowAddOrUpdate(SysUserDTO dto) {
        if (StrUtil.isNotBlank(dto.getUsername()) && checkUsernameNotUnique(dto.getUserId(), dto.getUsername())) {
            throw new ServiceException("登录账号已存在");
        }
        if (StrUtil.isNotBlank(dto.getPhone()) && checkPhoneNotUnique(dto.getUserId(), dto.getPhone())) {
            throw new ServiceException("手机号已存在");
        }
        if (StrUtil.isNotBlank(dto.getEmail()) && checkEmailNotUnique(dto.getUserId(), dto.getEmail())) {
            throw new ServiceException("邮箱号已存在");
        }
    }

    @Override
    public SysUserVO selectVoByUsername(String username, boolean hasPassword) {
        SysUser sysUser = sysUserMapper.selectOne(SysUserConverter.username2Wrapper(username));
        if (Objects.nonNull(sysUser)) {
            SysUserVO sysUserVO = SysUserConverter.entity2Vo(sysUser);
            if (!hasPassword) {
                sysUserVO.setPassword(null);
            }
            return sysUserVO;
        }
        return null;
    }

    @Override
    public void updateLastLoginInfo(String userId, String ip, Date loginTime) {
        SysUser sysUser = new SysUser();
        sysUser.setUserId(userId);
        sysUser.setLastLoginIp(ip);
        sysUser.setLastLoginTime(loginTime);
        sysUserMapper.updateById(sysUser);
    }

    private boolean checkUsernameNotUnique(String userId, String username) {
        return StrUtil.isNotBlank(sysUserMapper.checkUsernameUnique(userId, username));
    }

    private boolean checkPhoneNotUnique(String userId, String phone) {
        return StrUtil.isNotBlank(sysUserMapper.checkPhoneUnique(userId, phone));
    }

    private boolean checkEmailNotUnique(String userId, String email) {
        return StrUtil.isNotBlank(sysUserMapper.checkEmailUnique(userId, email));
    }
}
